package main

//
//import (
//	"fmt"
//	"math"
//	"sort"
//	"time"
//)
//
//const (
//	// 时间格式，方便解析和打印
//	TimeLayout = "2006-01-02 15:04:05"
//	HourLayout = "15:04"
//)
//
//// --- 核心常量 (可配置) ---
//const (
//	MinSafeLevelM3      = 2.0           // 最低安全水量 (m³)
//	MaxSafeLevelM3      = 12.0          // 最高安全水量 (m³)
//	InflowRateM3PerHour = 4.0           // 进水速度 (m³/h)
//	PlanningHorizon     = 3 * time.Hour // 每次规划的核心时间窗口
//
//	// 【新增】魔法数字常量化 - 提高代码可读性
//	MinRefillAmountM3    = 0.01            // 最小补水量阈值 (m³)
//	MinAvailableHours    = 0.5             // 最小可用时间 (小时)
//	MaxAdjustAttempts    = 10              // 调度器最大调整尝试次数
//	ConsecutiveGapLimit  = 5 * time.Minute // 判断连续禁补时段的最大间隔
//	OverflowSafetyMargin = 0.1             // 防溢出安全边际
//)
//
//// --- 数值处理辅助函数 ---
//
//// round2 保留2位小数
//func round2(value float64) float64 {
//	return math.Round(value*100) / 100
//}
//
//// multiply 乘法运算，结果保留2位小数
//func multiply(a, b float64) float64 {
//	return round2(a * b)
//}
//
//// divide 除法运算，结果保留2位小数
//func divide(a, b float64) float64 {
//	if b == 0 {
//		return 0
//	}
//	return round2(a / b)
//}
//
//// --- 日志级别定义 ---
//type LogLevel int
//
//const (
//	LogLevelError LogLevel = iota // 错误级别
//	LogLevelWarn                  // 警告级别
//	LogLevelInfo                  // 信息级别
//	LogLevelDebug                 // 调试级别
//)
//
//// 全局日志级别，可在生产环境中设置为 LogLevelWarn 或 LogLevelError
//var currentLogLevel = LogLevelDebug
//
//// logMessage 统一的日志输出函数
//func logMessage(level LogLevel, format string, args ...interface{}) {
//	if level <= currentLogLevel {
//		prefix := ""
//		switch level {
//		case LogLevelError:
//			prefix = "[ERROR] "
//		case LogLevelWarn:
//			prefix = "[WARN]  "
//		case LogLevelInfo:
//			prefix = "[INFO]  "
//		case LogLevelDebug:
//			prefix = "[DEBUG] "
//		}
//		fmt.Printf(prefix+format, args...)
//	}
//}
//
//// 【新增】辅助函数：打印分隔线
//func logSeparator(level LogLevel, char string, length int) {
//	if level <= currentLogLevel {
//		separator := ""
//		for i := 0; i < length; i++ {
//			separator += char
//		}
//		logMessage(level, "%s\n", separator)
//	}
//}
//
//// 【新增】辅助函数：打印标题
//func logTitle(level LogLevel, title string) {
//	if level <= currentLogLevel {
//		logSeparator(level, "=", 60)
//		logMessage(level, "   %s\n", title)
//		logSeparator(level, "=", 60)
//	}
//}
//
//// 【新增】辅助函数：打印子标题
//func logSubTitle(level LogLevel) {
//	if level <= currentLogLevel {
//		logSeparator(level, "-", 60)
//	}
//}
//
//// --- 数据结构定义 ---
//
//// TimeRange 定义一个时间范围
//type TimeRange struct {
//	Start time.Time
//	End   time.Time
//}
//
//// Contains 检查给定时间是否在此范围内 [Start, End)
//func (tr TimeRange) Contains(t time.Time) bool {
//	return !t.Before(tr.Start) && t.Before(tr.End)
//}
//
//// TargetedTimeRange 带目标水位的特殊时间段
//type TargetedTimeRange struct {
//	TimeRange
//	TargetLevelM3 float64
//}
//
//// UserRules 用户自定义的规则
//type UserRules struct {
//	PriorityPeriods  []TargetedTimeRange // 优先补水
//	PeakPeriods      []TargetedTimeRange // 用水高峰
//	ForbiddenPeriods []TimeRange         // 不可补水
//}
//
//// SystemState 某一时刻的系统状态，作为规划器的输入
//type SystemState struct {
//	CurrentTime         time.Time
//	CurrentLevelM3      float64
//	Prediction3h        []float64 // 未来24小时的8个3h步长预测用水量
//	Prediction30min     []float64 // 未来24小时的48个30min步长预测用水量
//	NextDayPrediction3h []float64 // [可选] 第二天 00:00-06:00 的预测
//	BlockStartTime      time.Time // 【新增】第一个预测块的标准起始时间（如09:00）
//}
//
//// ReplenishmentTask 生成的补水任务
//type ReplenishmentTask struct {
//	StartTime time.Time
//	EndTime   time.Time
//	AmountM3  float64
//	Reason    string // 任务生成原因，便于调试和追踪
//	Priority  string // 任务优先级
//}
//
//// ScheduleError 调度错误信息
//type ScheduleError struct {
//	Code    string
//	Message string
//}
//
//func (e *ScheduleError) Error() string {
//	return fmt.Sprintf("[%s] %s", e.Code, e.Message)
//}
//
//// 【新增】PlanningPeriod 规划周期，包含实际的开始和结束时间
//type PlanningPeriod struct {
//	Start         time.Time
//	End           time.Time
//	IsPartial     bool      // 是否是部分时间块
//	BlockIndex    int       // 在预测数组中的索引
//	BlockStart    time.Time // 该块的标准开始时间（如09:00）
//	UsageFraction float64   // 使用该块预测值的比例（用于部分时间块）
//}
//
//// Planner 智能补水计划器
//type Planner struct {
//	rules        UserRules
//	minSafeLevel float64
//	maxSafeLevel float64
//	inflowRate   float64
//}
//
//// NewPlanner 创建一个新的计划器实例
//func NewPlanner(rules UserRules, min, max, inflow float64) *Planner {
//	if inflow <= 0 {
//		panic("Planner creation failed: inflowRate must be a positive number.")
//	}
//	return &Planner{
//		rules:        rules,
//		minSafeLevel: min,
//		maxSafeLevel: max,
//		inflowRate:   inflow,
//	}
//}
//
//// GenerateLastPlan 生成21:00-24:00的补水计划
//func (p *Planner) GenerateLastPlan(state SystemState) *ReplenishmentTask {
//	logMessage(LogLevelInfo, "\n--- [SPECIAL PLANNING - LAST PERIOD] at %s ---\n", state.CurrentTime.Format(TimeLayout))
//
//	nextDayPrediction3h := state.NextDayPrediction3h
//	if len(nextDayPrediction3h) == 0 {
//		logMessage(LogLevelWarn, "Warning: No next-day prediction available. Using current prediction instead.\n")
//
//		if len(state.Prediction3h) >= 2 {
//			nextDayPrediction3h = state.Prediction3h[len(state.Prediction3h)-2:]
//		} else {
//			nextDayPrediction3h = []float64{2.0, 2.0}
//		}
//	}
//
//	usageNextMorning := nextDayPrediction3h[0] + nextDayPrediction3h[1]
//	logMessage(LogLevelDebug, "  - Next day's morning (00:00-06:00) predicted usage: %.2f m³\n", usageNextMorning)
//
//	targetLevelAtMidnight := usageNextMorning + p.minSafeLevel
//	logMessage(LogLevelDebug, "  - Target level at midnight: %.2f m³ (Usage) + %.2f m³ (Safe) = %.2f m³\n",
//		usageNextMorning, p.minSafeLevel, targetLevelAtMidnight)
//
//	usageCurrentPeriod := 0.0
//	if len(state.Prediction3h) > 0 {
//		usageCurrentPeriod = state.Prediction3h[0]
//	}
//
//	logMessage(LogLevelDebug, "  - Current period predicted usage: %.2f m³\n", usageCurrentPeriod)
//
//	predictedLevelAtMidnight := state.CurrentLevelM3 - usageCurrentPeriod
//
//	amountNeeded := targetLevelAtMidnight - predictedLevelAtMidnight
//	logMessage(LogLevelDebug, "  - Amount needed: %.2f m³ (Target) - %.2f m³ (Predicted) = %.2f m³\n",
//		targetLevelAtMidnight, predictedLevelAtMidnight, amountNeeded)
//
//	if amountNeeded <= MinRefillAmountM3 {
//		logMessage(LogLevelInfo, "Conclusion: No special replenishment needed for the next day.\n")
//		return nil
//	}
//
//	isSafety := predictedLevelAtMidnight >= p.minSafeLevel
//	task := p.scheduleTask(state, amountNeeded, isSafety, "为第二天凌晨准备")
//
//	if task == nil {
//		logMessage(LogLevelWarn, "Conclusion: Replenishment was needed for the next day, but scheduler could not find a valid time slot.\n")
//		return nil
//	}
//
//	usageUntilTaskEnd := SumPredictedUsage(state.CurrentTime, state.CurrentTime, task.EndTime, state.Prediction3h)
//	predictedEndLevel := state.CurrentLevelM3 + task.AmountM3 - usageUntilTaskEnd
//
//	if predictedEndLevel > p.maxSafeLevel {
//		overflowAmount := predictedEndLevel - p.maxSafeLevel
//		logMessage(LogLevelWarn, "  - Final Correction: Reducing refill by %.2f m³ due to overflow risk.\n", overflowAmount)
//		task.AmountM3 = round2(task.AmountM3 - overflowAmount)
//		task.AmountM3 = math.Max(0, task.AmountM3)
//
//		if task.AmountM3 <= MinRefillAmountM3 {
//			logMessage(LogLevelWarn, "Conclusion: Task canceled after final overflow correction.\n")
//			return nil
//		}
//	}
//
//	logMessage(LogLevelInfo, "Conclusion: Special replenishment task for next day generated.\n")
//	return task
//}
//
//// GeneratePlan 是主入口函数，根据当前系统状态生成一个补水计划
//func (p *Planner) GeneratePlan(state SystemState) *ReplenishmentTask {
//	logMessage(LogLevelInfo, "\n--- [PLANNING] at %s ---\n", state.CurrentTime.Format(TimeLayout))
//
//	// ========== 第一轮：需求计算 ==========
//	logMessage(LogLevelDebug, "\n=== 第一轮：需求计算 ===\n")
//
//	safetyReq := p.calculateSafetyRequirement(state)
//	logMessage(LogLevelDebug, "V_req_safety: %.2f m³\n", safetyReq)
//
//	proactiveReq := p.calculateProactiveRequirement(state)
//	logMessage(LogLevelDebug, "V_req_proactive: %.2f m³\n", proactiveReq)
//
//	opportunityReq := p.calculateOpportunityRequirement(state)
//	logMessage(LogLevelDebug, "V_req_opportunity: %.2f m³\n", opportunityReq)
//
//	// ========== 第二轮：决策合成 ==========
//	logMessage(LogLevelDebug, "\n=== 第二轮：决策合成 ===\n")
//
//	baseNeeded := math.Max(safetyReq, proactiveReq)
//	logMessage(LogLevelDebug, "V_base_needed: %.2f m³\n", baseNeeded)
//
//	theoreticalAmount := math.Max(baseNeeded, opportunityReq)
//	logMessage(LogLevelDebug, "Theoretical V_final (before scheduling & correction): %.2f m³\n", theoreticalAmount)
//
//	if theoreticalAmount < MinRefillAmountM3 {
//		logMessage(LogLevelInfo, "Conclusion: No replenishment needed based on requirements.\n")
//		return nil
//	}
//
//	// ========== 第三轮：任务调度 ==========
//	logMessage(LogLevelDebug, "\n=== 第三轮：任务调度与时间检查 ===\n")
//
//	reason := "常规补水"
//	if safetyReq > 0 {
//		reason = "安全需求"
//	} else if proactiveReq > 0 {
//		reason = "前瞻性准备"
//	} else if opportunityReq > 0 {
//		reason = "优先补水机会"
//	}
//
//	isSafety := safetyReq == 0
//	task := p.scheduleTask(state, theoreticalAmount, isSafety, reason)
//	if task == nil {
//		logMessage(LogLevelWarn, "Conclusion: Replenishment was needed, but scheduler could not find a valid time slot.\n")
//		return nil
//	}
//
//	requiredDuration := divide(theoreticalAmount, p.inflowRate)
//	actualDuration := task.EndTime.Sub(task.StartTime).Hours()
//
//	if requiredDuration > multiply(actualDuration, 1.1) {
//		shortage := multiply(requiredDuration-actualDuration, p.inflowRate)
//		logMessage(LogLevelWarn, "  - WARNING: Insufficient time! Theoretical amount %.2f m³ needs %.2f h, but only %.2f h available. Short by %.2f m³\n",
//			theoreticalAmount, requiredDuration, actualDuration, shortage)
//
//		task.AmountM3 = multiply(actualDuration, p.inflowRate)
//		logMessage(LogLevelInfo, "  - Adjusted task amount to %.2f m³ (max capacity in available time)\n", task.AmountM3)
//	}
//
//	// ========== 第四轮：最终校验 ==========
//	logMessage(LogLevelDebug, "\n=== 第四轮：最终校验 ===\n")
//
//	usageUntilTaskEnd := SumPredictedUsage(state.CurrentTime, state.CurrentTime, task.EndTime, state.Prediction3h)
//	predictedEndLevel := state.CurrentLevelM3 + task.AmountM3 - usageUntilTaskEnd
//
//	if predictedEndLevel > p.maxSafeLevel {
//		overflowAmount := predictedEndLevel - p.maxSafeLevel
//		logMessage(LogLevelWarn, "  - Final Correction: At task end (%s), predicted level %.2f m³ would exceed max safe level %.2f m³. Reducing refill by %.2f m³.\n",
//			task.EndTime.Format(HourLayout), predictedEndLevel, p.maxSafeLevel, overflowAmount)
//
//		task.AmountM3 = round2(task.AmountM3 - overflowAmount)
//		task.AmountM3 = math.Max(0, task.AmountM3)
//
//		if task.AmountM3 <= MinRefillAmountM3 {
//			logMessage(LogLevelWarn, "Conclusion: Task canceled after final overflow correction.\n")
//			return nil
//		}
//	}
//
//	logMessage(LogLevelInfo, "Conclusion: Replenishment task generated.\n")
//	return task
//}
//
//// calculateSafetyRequirement 计算安全需求
//func (p *Planner) calculateSafetyRequirement(state SystemState) float64 {
//	if len(state.Prediction3h) == 0 {
//		return 0.0
//	}
//
//	usageNext3h := state.Prediction3h[0]
//	predictedLevelAtEnd := state.CurrentLevelM3 - usageNext3h
//
//	if predictedLevelAtEnd < p.minSafeLevel {
//		return round2(p.minSafeLevel - predictedLevelAtEnd)
//	}
//
//	return 0
//}
//
//// calculateProactiveRequirement 计算前瞻性需求
//func (p *Planner) calculateProactiveRequirement(state SystemState) float64 {
//	forbidPrep := p.calculateForbidPrep(state)
//	logMessage(LogLevelDebug, "  - V_forbid_prep: %.2f m³\n", forbidPrep)
//
//	peakPrep := p.calculatePeakPrep(state)
//	logMessage(LogLevelDebug, "  - V_peak_prep: %.2f m³\n", peakPrep)
//
//	return math.Max(forbidPrep, peakPrep)
//}
//
//// calculateForbidPrep 为不可补水时段做准备
//func (p *Planner) calculateForbidPrep(state SystemState) float64 {
//	nextForbid, found := findNextPeriod(state.CurrentTime, p.rules.ForbiddenPeriods)
//	if !found {
//		return 0
//	}
//
//	usageUntilForbid := SumPredictedUsage(state.CurrentTime, state.CurrentTime, nextForbid.Start, state.Prediction3h)
//
//	totalForbidUsage := 0.0
//	currentForbidEnd := nextForbid.End
//	consecutiveCount := 1
//
//	logMessage(LogLevelDebug, "    - Analyzing consecutive forbidden periods starting from %s:\n", nextForbid.Start.Format(HourLayout))
//
//	usageDuringForbid := SumPredictedUsage(state.CurrentTime, nextForbid.Start, nextForbid.End, state.Prediction3h)
//	totalForbidUsage = round2(totalForbidUsage + usageDuringForbid)
//	logMessage(LogLevelDebug, "      [%d] %s -> %s: %.2f m³\n",
//		consecutiveCount, nextForbid.Start.Format(HourLayout), nextForbid.End.Format(HourLayout), usageDuringForbid)
//
//	for {
//		nextConsecutiveForbid, found := findImmediateNextPeriod(currentForbidEnd, p.rules.ForbiddenPeriods)
//		if !found {
//			break
//		}
//
//		gap := nextConsecutiveForbid.Start.Sub(currentForbidEnd)
//		if gap > ConsecutiveGapLimit {
//			logMessage(LogLevelDebug, "      - Gap of %.1f minutes detected. Not consecutive.\n", gap.Minutes())
//			break
//		}
//
//		consecutiveCount++
//		usageDuringThisForbid := SumPredictedUsage(state.CurrentTime, nextConsecutiveForbid.Start, nextConsecutiveForbid.End, state.Prediction3h)
//		totalForbidUsage = round2(totalForbidUsage + usageDuringThisForbid)
//		logMessage(LogLevelDebug, "      [%d] %s -> %s: %.2f m³ (consecutive)\n",
//			consecutiveCount, nextConsecutiveForbid.Start.Format(HourLayout), nextConsecutiveForbid.End.Format(HourLayout), usageDuringThisForbid)
//
//		currentForbidEnd = nextConsecutiveForbid.End
//	}
//
//	logMessage(LogLevelDebug, "    - Total consecutive forbidden periods: %d, total usage: %.2f m³\n", consecutiveCount, totalForbidUsage)
//
//	minLevelAtForbidStart := totalForbidUsage + p.minSafeLevel
//	predictedLevelAtForbidStart := state.CurrentLevelM3 - usageUntilForbid
//	totalDeficit := minLevelAtForbidStart - predictedLevelAtForbidStart
//
//	if totalDeficit <= 0 {
//		return 0
//	}
//
//	windowStart := state.CurrentTime.Add(PlanningHorizon)
//	windowEnd := nextForbid.Start
//	futureCapacity := p.calculateFutureRefillCapacity(windowStart, windowEnd, p.rules)
//	remainingDeficit := totalDeficit - futureCapacity
//
//	return math.Max(0, round2(remainingDeficit))
//}
//
//// calculatePeakPrep 为用水高峰做准备
//func (p *Planner) calculatePeakPrep(state SystemState) float64 {
//	nextPeak, found := findNextTargetedPeriod(state.CurrentTime, p.rules.PeakPeriods)
//	if !found {
//		return 0
//	}
//
//	usageUntilPeak := SumPredictedUsage(state.CurrentTime, state.CurrentTime, nextPeak.Start, state.Prediction3h)
//	predictedLevelAtPeakStart := state.CurrentLevelM3 - usageUntilPeak
//	totalDeficit := nextPeak.TargetLevelM3 - predictedLevelAtPeakStart
//
//	if totalDeficit <= 0 {
//		return 0
//	}
//
//	windowStart := state.CurrentTime.Add(PlanningHorizon)
//	windowEnd := nextPeak.Start
//	futureCapacity := p.calculateFutureRefillCapacity(windowStart, windowEnd, p.rules)
//	remainingDeficit := totalDeficit - futureCapacity
//
//	return math.Max(0, round2(remainingDeficit))
//}
//
//// calculateOpportunityRequirement 计算机会性需求
//// 【修改】对跨窗口的优先时段进行截取，并调整目标水位
//func (p *Planner) calculateOpportunityRequirement(state SystemState) float64 {
//	planningWindow := TimeRange{Start: state.CurrentTime, End: state.CurrentTime.Add(PlanningHorizon)}
//
//	// 找出所有与规划窗口有交集的优先时段，并进行截取
//	var overlappingPeriods []TargetedTimeRange
//	for _, period := range p.rules.PriorityPeriods {
//		// 计算时段与规划窗口的交集
//		actualStart := period.Start
//		if actualStart.Before(planningWindow.Start) {
//			actualStart = planningWindow.Start
//		}
//
//		actualEnd := period.End
//		needsAdjustment := false
//		if actualEnd.After(planningWindow.End) {
//			actualEnd = planningWindow.End
//			needsAdjustment = true // 标记需要调整目标
//		}
//
//		// 检查是否有有效的交集
//		if actualStart.Before(actualEnd) && actualEnd.After(planningWindow.Start) {
//			adjustedTarget := period.TargetLevelM3
//
//			// 【关键】如果时段跨越窗口边界，需要调整目标水位
//			if needsAdjustment {
//				// 计算窗口结束到原时段结束之间的预测用水量
//				futureUsage := SumPredictedUsage(state.CurrentTime, actualEnd, period.End, state.Prediction3h)
//				// 调整后的目标 = 原目标 + 未来用水量
//				// 这样可以确保到窗口结束时有足够的水来应对后续用水
//				adjustedTarget = round2(period.TargetLevelM3 + futureUsage)
//
//				logMessage(LogLevelDebug, "      Period [%s -> %s] crosses window boundary, truncated to [%s -> %s]\n",
//					period.Start.Format(HourLayout), period.End.Format(HourLayout),
//					actualStart.Format(HourLayout), actualEnd.Format(HourLayout))
//				logMessage(LogLevelDebug, "      Original target: %.2f m³, Future usage (%s -> %s): %.2f m³, Adjusted target: %.2f m³\n",
//					period.TargetLevelM3, actualEnd.Format(HourLayout), period.End.Format(HourLayout),
//					futureUsage, adjustedTarget)
//			}
//
//			adjustedPeriod := TargetedTimeRange{
//				TimeRange:     TimeRange{Start: actualStart, End: actualEnd},
//				TargetLevelM3: adjustedTarget,
//			}
//			overlappingPeriods = append(overlappingPeriods, adjustedPeriod)
//		}
//	}
//
//	if len(overlappingPeriods) == 0 {
//		logMessage(LogLevelDebug, "    - No priority periods within current planning window [%s -> %s]\n",
//			planningWindow.Start.Format(HourLayout),
//			planningWindow.End.Format(HourLayout))
//		return 0
//	}
//
//	logMessage(LogLevelDebug, "    - Found %d priority period(s) within planning window [%s -> %s]\n",
//		len(overlappingPeriods),
//		planningWindow.Start.Format(HourLayout),
//		planningWindow.End.Format(HourLayout))
//
//	// 按结束时间排序，确保按时序处理
//	sort.Slice(overlappingPeriods, func(i, j int) bool {
//		return overlappingPeriods[i].End.Before(overlappingPeriods[j].End)
//	})
//
//	// 模拟补水轨迹，计算累积需求
//	cumulativeRefillNeeded := 0.0
//
//	for idx, period := range overlappingPeriods {
//		// 计算到该时段结束时的预测用水量
//		usageUntilEnd := SumPredictedUsage(state.CurrentTime, state.CurrentTime, period.End, state.Prediction3h)
//
//		// 计算如果现在补充cumulativeRefillNeeded水量后，到该时段结束时的水位
//		predictedLevelAtEnd := state.CurrentLevelM3 + cumulativeRefillNeeded - usageUntilEnd
//
//		// 计算该时段还需要多少水才能达到目标
//		amountNeeded := period.TargetLevelM3 - predictedLevelAtEnd
//
//		logMessage(LogLevelDebug, "      [%d] Period [%s -> %s] target=%.2f m³:\n",
//			idx+1, period.Start.Format(HourLayout), period.End.Format(HourLayout), period.TargetLevelM3)
//		logMessage(LogLevelDebug, "          Usage until end: %.2f m³\n", usageUntilEnd)
//		logMessage(LogLevelDebug, "          Predicted level (with %.2f m³ refill): %.2f m³\n",
//			cumulativeRefillNeeded, predictedLevelAtEnd)
//		logMessage(LogLevelDebug, "          Additional needed: %.2f m³\n", amountNeeded)
//
//		// 如果需要更多水，累加到总需求中
//		if amountNeeded > 0 {
//			cumulativeRefillNeeded = round2(cumulativeRefillNeeded + amountNeeded)
//			logMessage(LogLevelDebug, "          -> Cumulative refill updated to: %.2f m³\n", cumulativeRefillNeeded)
//		}
//	}
//
//	if cumulativeRefillNeeded <= 0 {
//		logMessage(LogLevelDebug, "    - Current trajectory already meets or exceeds all priority targets.\n")
//		return 0
//	}
//
//	// 检查规划窗口内的可用时间容量
//	availableHours := planningWindow.End.Sub(state.CurrentTime).Hours()
//	if availableHours < 0 {
//		availableHours = 0
//	}
//
//	maxCapacityInTime := multiply(availableHours, p.inflowRate)
//	logMessage(LogLevelDebug, "    - Available time in planning window: %.2f hours (%.2f m³ capacity)\n",
//		availableHours, maxCapacityInTime)
//
//	// 考虑防溢出：计算到规划窗口结束时的最大允许补水量
//	usageUntilWindowEnd := SumPredictedUsage(state.CurrentTime, state.CurrentTime, planningWindow.End, state.Prediction3h)
//	maxAllowableRefill := p.maxSafeLevel - (state.CurrentLevelM3 - usageUntilWindowEnd)
//
//	if maxAllowableRefill > 0 && maxAllowableRefill < maxCapacityInTime {
//		logMessage(LogLevelDebug, "    - Overflow protection: Limiting refill to %.2f m³ (to avoid exceeding %.2f m³)\n",
//			maxAllowableRefill, p.maxSafeLevel)
//		maxCapacityInTime = maxAllowableRefill
//	}
//
//	// 取累积需求和最大容量中的较小值
//	opportunityAmount := math.Min(cumulativeRefillNeeded, maxCapacityInTime)
//
//	logMessage(LogLevelDebug, "    - Final opportunity requirement: %.2f m³\n", opportunityAmount)
//	logMessage(LogLevelDebug, "      (Cumulative needed: %.2f m³, Capacity limit: %.2f m³)\n",
//		cumulativeRefillNeeded, maxCapacityInTime)
//
//	return math.Max(0, round2(opportunityAmount))
//}
//
//// calculateFutureRefillCapacity 计算在一个时间窗口内，理论上可补充的最大水量
//func (p *Planner) calculateFutureRefillCapacity(start, end time.Time, rules UserRules) float64 {
//	if !end.After(start) {
//		return 0.0
//	}
//
//	totalWindow := TimeRange{Start: start, End: end}
//	totalForbiddenDuration := time.Duration(0)
//
//	for _, forbidPeriod := range rules.ForbiddenPeriods {
//		overlap := intersectionDuration(totalWindow, forbidPeriod)
//		totalForbiddenDuration += overlap
//	}
//
//	totalDuration := totalWindow.End.Sub(totalWindow.Start)
//	refillableDuration := totalDuration - totalForbiddenDuration
//
//	if refillableDuration < 0 {
//		refillableDuration = 0
//	}
//
//	refillableHours := refillableDuration.Hours()
//
//	return round2(multiply(refillableHours, p.inflowRate))
//}
//
//// scheduleTask 调度具体的补水任务
//func (p *Planner) scheduleTask(state SystemState, amountM3 float64, isSafety bool, reason string) *ReplenishmentTask {
//	planningWindowStart := state.CurrentTime
//	planningWindowEnd := state.CurrentTime.Add(PlanningHorizon)
//	maxPossibleRefill := p.calculateFutureRefillCapacity(planningWindowStart, planningWindowEnd, p.rules)
//
//	adjustedAmountM3 := amountM3
//	if adjustedAmountM3 > maxPossibleRefill {
//		logMessage(LogLevelWarn, "  - Scheduler WARNING: Required refill (%.2f m³) exceeds max capacity (%.2f m³). Capping amount.\n",
//			adjustedAmountM3, maxPossibleRefill)
//		adjustedAmountM3 = maxPossibleRefill
//	}
//
//	if adjustedAmountM3 <= MinRefillAmountM3 {
//		logMessage(LogLevelDebug, "  - Scheduler: Adjusted amount too small (%.4f m³), canceling task.\n", adjustedAmountM3)
//		return nil
//	}
//
//	durationHours := divide(adjustedAmountM3, p.inflowRate)
//	taskDuration := time.Duration(multiply(durationHours, float64(time.Hour)))
//	if taskDuration <= 0 {
//		return nil
//	}
//
//	var startTime, endTime time.Time
//	isASAP := !isSafety
//
//	if isASAP {
//		logMessage(LogLevelDebug, "  - Scheduler Strategy: Safety requirement. Aligning to start (ASAP).\n")
//		startTime = planningWindowStart
//		endTime = startTime.Add(taskDuration)
//	} else {
//		logMessage(LogLevelDebug, "  - Scheduler Strategy: Non-urgent condition. Aligning to end (ALAP).\n")
//		endTime = planningWindowEnd
//		startTime = endTime.Add(-taskDuration)
//	}
//
//	for i := 0; i < MaxAdjustAttempts; i++ {
//		proposedTaskRange := TimeRange{Start: startTime, End: endTime}
//		conflictingForbidPeriod, hasConflict := p.findConflict(proposedTaskRange, p.rules.ForbiddenPeriods)
//
//		if !hasConflict {
//			break
//		}
//
//		logMessage(LogLevelDebug, "  - Scheduler: Plan [%s -> %s] conflicts with forbidden period [%s -> %s]. Adjusting...\n",
//			startTime.Format(HourLayout), endTime.Format(HourLayout),
//			conflictingForbidPeriod.Start.Format(HourLayout), conflictingForbidPeriod.End.Format(HourLayout))
//
//		if isASAP {
//			newStartTime := conflictingForbidPeriod.End
//			newEndTime := newStartTime.Add(taskDuration)
//
//			if newEndTime.After(planningWindowEnd) {
//				logMessage(LogLevelError, "  - Scheduler ERROR: Not enough time to schedule after the forbidden period.\n")
//				return nil
//			}
//			startTime, endTime = newStartTime, newEndTime
//		} else {
//			newEndTime := conflictingForbidPeriod.Start
//			newStartTime := newEndTime.Add(-taskDuration)
//
//			if newStartTime.Before(planningWindowStart) {
//				logMessage(LogLevelError, "  - Scheduler ERROR: Not enough time to schedule before the forbidden period.\n")
//				return nil
//			}
//			startTime, endTime = newStartTime, newEndTime
//		}
//
//		if i == MaxAdjustAttempts-1 {
//			logMessage(LogLevelError, "  - Scheduler ERROR: Failed to find a conflict-free slot after %d attempts.\n", MaxAdjustAttempts)
//			return nil
//		}
//	}
//
//	if startTime.Before(planningWindowStart) || endTime.After(planningWindowEnd) {
//		logMessage(LogLevelError, "  - Scheduler ERROR: Final task [%s -> %s] is out of planning window.\n",
//			startTime.Format(HourLayout), endTime.Format(HourLayout))
//		return nil
//	}
//
//	priority := "P4-常规"
//	if !isSafety {
//		priority = "P0-紧急"
//	} else if reason == "前瞻性准备" {
//		priority = "P1-前瞻"
//	} else if reason == "优先补水机会" {
//		priority = "P2-优先"
//	}
//
//	return &ReplenishmentTask{
//		StartTime: startTime,
//		EndTime:   endTime,
//		AmountM3:  round2(adjustedAmountM3),
//		Reason:    reason,
//		Priority:  priority,
//	}
//}
//
//// findConflict 用于查找时间冲突
//func (p *Planner) findConflict(taskRange TimeRange, forbiddenPeriods []TimeRange) (TimeRange, bool) {
//	for _, forbid := range forbiddenPeriods {
//		if intersectionDuration(taskRange, forbid) > 0 {
//			return forbid, true
//		}
//	}
//	return TimeRange{}, false
//}
//
//// --- 辅助函数 ---
//
//// findNextPeriod 查找未来24小时内最近的一个时间段
//func findNextPeriod(currentTime time.Time, periods []TimeRange) (TimeRange, bool) {
//	var nextPeriod TimeRange
//	found := false
//	minDiff := 25 * time.Hour
//
//	for _, p := range periods {
//		if p.Start.After(currentTime) {
//			diff := p.Start.Sub(currentTime)
//			if diff < minDiff {
//				minDiff = diff
//				nextPeriod = p
//				found = true
//			}
//		}
//	}
//	return nextPeriod, found
//}
//
//// findNextTargetedPeriod 查找未来24小时内最近的一个带目标的时间段
//func findNextTargetedPeriod(fromTime time.Time, periods []TargetedTimeRange) (TargetedTimeRange, bool) {
//	var nextPeriod TargetedTimeRange
//	found := false
//	minDiff := 25 * time.Hour
//
//	for _, p := range periods {
//		if p.Start.After(fromTime) {
//			diff := p.Start.Sub(fromTime)
//			if diff < minDiff {
//				minDiff = diff
//				nextPeriod = p
//				found = true
//			}
//		}
//	}
//	return nextPeriod, found
//}
//
//// findImmediateNextPeriod 查找紧接着的下一个时段（用于检测连续禁补）
//func findImmediateNextPeriod(afterTime time.Time, periods []TimeRange) (TimeRange, bool) {
//	var nextPeriod TimeRange
//	found := false
//	minDiff := 25 * time.Hour
//
//	for _, p := range periods {
//		if p.Start.After(afterTime) || p.Start.Equal(afterTime) {
//			diff := p.Start.Sub(afterTime)
//			if diff < minDiff {
//				minDiff = diff
//				nextPeriod = p
//				found = true
//			}
//		}
//	}
//
//	return nextPeriod, found
//}
//
//// SumPredictedUsage 计算一个时间段内的预测总用水量
//// 【重要修复】支持部分块的正确计算
//// @param currentTime    当前实际时间（可能在块中间，如09:30）
//// @param start          需要计算总用水量的开始时间
//// @param end            需要计算总用水量的结束时间
//// @param prediction3h   从blockStartTime开始的预测数组（如果当前在部分块中，[0]是调整后的值）
//func SumPredictedUsage(currentTime, start, end time.Time, prediction3h []float64) float64 {
//	if !end.After(start) {
//		return 0.0
//	}
//
//	if start.Before(currentTime) {
//		start = currentTime
//	}
//
//	totalUsage := 0.0
//
//	// 【关键修复】第一个预测块从currentTime开始，后续块从标准边界开始
//	// 计算第一个块的结束时间（对齐到下一个3小时整点）
//	firstBlockEnd := getNextStandardTimeBlock(currentTime)
//
//	// 使用currentTime作为第0块的起始基准
//	startOffsetHours := start.Sub(currentTime).Hours()
//	startIndex := int(math.Floor(divide(startOffsetHours, 3.0)))
//
//	endOffsetHours := end.Sub(currentTime).Hours()
//	endIndex := int(math.Floor(divide(endOffsetHours, 3.0)))
//
//	if startIndex >= len(prediction3h) {
//		if len(prediction3h) == 0 {
//			logMessage(LogLevelWarn, "Warning: No prediction data available. Cannot estimate usage.\n")
//			return 0.0
//		}
//
//		lastValue := prediction3h[len(prediction3h)-1]
//		estimatedUsage := multiply(lastValue, divide(end.Sub(start).Hours(), 3.0))
//		logMessage(LogLevelWarn, "Warning: Usage prediction beyond available data (start index %d >= length %d). Estimating %.2f m³ with last value.\n",
//			startIndex, len(prediction3h), estimatedUsage)
//		return round2(estimatedUsage)
//	}
//
//	needsExtrapolation := false
//	extrapolationStart := time.Time{}
//
//	if endIndex >= len(prediction3h) {
//		// 外推意味着：预测数据不足。例如：currentTime: 2023-10-27 09:30:00 (预测生成的时间)、prediction3h: []float64{4.5, 6.0} (只有两个预测块)，分别为（09:30 - 12:00、 12:00 - 15:00）
//		// 在上述情况下，用户发起的查询为：start: 2023-10-27 16:00:00、end: 2023-10-27 17:00:00
//		needsExtrapolation = true
//		// 外推起点：第一块结束时间 + 剩余完整块数量 * 3小时
//		extrapolationStart = firstBlockEnd.Add(time.Duration(len(prediction3h)-1) * time.Hour * 3)
//		endIndex = len(prediction3h) - 1
//		logMessage(LogLevelDebug, "Notice: End time extends beyond prediction data. Will extrapolate from %s.\n", extrapolationStart.Format(HourLayout))
//	}
//
//	if startIndex == endIndex {
//		// start 和 end 在同一个块内
//		blockUsage := prediction3h[startIndex]
//
//		// 【修复】计算块的实际边界
//		var blockStart, blockEnd time.Time
//		if startIndex == 0 {
//			// 第一个块：从currentTime到firstBlockEnd
//			blockStart = currentTime
//			blockEnd = firstBlockEnd
//		} else {
//			// 后续块：标准3小时块
//			blockStart = firstBlockEnd.Add(time.Duration(startIndex-1) * time.Hour * 3)
//			blockEnd = blockStart.Add(time.Hour * 3)
//		}
//
//		// 计算实际使用的时间段
//		actualStart := start
//		if actualStart.Before(blockStart) {
//			actualStart = blockStart
//		}
//		actualEnd := end
//		if actualEnd.After(blockEnd) {
//			actualEnd = blockEnd
//		}
//
//		// 计算占该块的比例
//		usedDuration := actualEnd.Sub(actualStart).Hours()
//		blockDuration := blockEnd.Sub(blockStart).Hours()
//		proportion := divide(usedDuration, blockDuration)
//
//		totalUsage = multiply(blockUsage, proportion)
//
//	} else {
//		// 跨越多个块
//
//		// 1. 处理起始块（部分使用）
//		if startIndex < len(prediction3h) {
//			var blockStart, blockEnd time.Time
//			if startIndex == 0 {
//				// 第一个块：从currentTime到firstBlockEnd
//				blockStart = currentTime
//				blockEnd = firstBlockEnd
//			} else {
//				// 后续块：标准3小时块
//				blockStart = firstBlockEnd.Add(time.Duration(startIndex-1) * time.Hour * 3)
//				blockEnd = blockStart.Add(time.Hour * 3)
//			}
//
//			actualStart := start
//			if actualStart.Before(blockStart) {
//				actualStart = blockStart
//			}
//
//			usedDuration := blockEnd.Sub(actualStart).Hours()
//			blockDuration := blockEnd.Sub(blockStart).Hours()
//			proportionStart := divide(usedDuration, blockDuration)
//
//			totalUsage = round2(totalUsage + multiply(prediction3h[startIndex], proportionStart))
//		}
//
//		// 2. 处理中间的完整块
//		for i := startIndex + 1; i < endIndex; i++ {
//			if i < len(prediction3h) {
//				totalUsage = round2(totalUsage + prediction3h[i])
//			}
//		}
//
//		// 3. 处理结束块（部分使用）
//		if endIndex < len(prediction3h) {
//			var blockStart, blockEnd time.Time
//			if endIndex == 0 {
//				// 第一个块：从currentTime到firstBlockEnd
//				blockStart = currentTime
//				blockEnd = firstBlockEnd
//			} else {
//				// 后续块：标准3小时块
//				blockStart = firstBlockEnd.Add(time.Duration(endIndex-1) * time.Hour * 3)
//				blockEnd = blockStart.Add(time.Hour * 3)
//			}
//
//			actualEnd := end
//			if needsExtrapolation && extrapolationStart.Before(end) {
//				actualEnd = extrapolationStart
//			}
//			if actualEnd.After(blockEnd) {
//				actualEnd = blockEnd
//			}
//
//			usedDuration := actualEnd.Sub(blockStart).Hours()
//			blockDuration := blockEnd.Sub(blockStart).Hours()
//			proportionEnd := divide(usedDuration, blockDuration)
//
//			totalUsage = round2(totalUsage + multiply(prediction3h[endIndex], proportionEnd))
//		}
//
//		// 4. 处理外推部分
//		if needsExtrapolation {
//			lastValue := prediction3h[len(prediction3h)-1]
//			extraDuration := end.Sub(extrapolationStart).Hours()
//			extraUsage := multiply(lastValue, divide(extraDuration, 3.0))
//			totalUsage = round2(totalUsage + extraUsage)
//			logMessage(LogLevelDebug, "  - Extrapolated %.2f m³ for period beyond prediction data.\n", extraUsage)
//		}
//	}
//
//	if totalUsage < 0 {
//		return 0.0
//	}
//
//	return round2(totalUsage)
//}
//
//// intersectionDuration 计算两个时间段的交集
//func intersectionDuration(r1, r2 TimeRange) time.Duration {
//	latestStart := r1.Start
//	if r2.Start.After(latestStart) {
//		latestStart = r2.Start
//	}
//
//	earliestEnd := r1.End
//	if r2.End.Before(earliestEnd) {
//		earliestEnd = r2.End
//	}
//
//	if !latestStart.Before(earliestEnd) {
//		return 0
//	}
//
//	return earliestEnd.Sub(latestStart)
//}
//
//// ============================================================================
//// 【新增】全天规划器相关代码
//// ============================================================================
//
//// getCurrentStandardBlock 获取当前时间所在的标准3小时块
//// 返回该块的开始时间、结束时间和索引
//func getCurrentStandardBlock(currentTime time.Time) (time.Time, time.Time, int) {
//	// 标准时间块的小时数
//	standardHours := []int{0, 3, 6, 9, 12, 15, 18, 21}
//
//	currentHour := currentTime.Hour()
//
//	// 找到当前时间所在的标准块
//	for i, hour := range standardHours {
//		nextHour := 24
//		if i < len(standardHours)-1 {
//			nextHour = standardHours[i+1]
//		}
//
//		if currentHour >= hour && currentHour < nextHour {
//			// 找到了当前所在的块
//			blockStart := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(),
//				hour, 0, 0, 0, currentTime.Location())
//			blockEnd := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(),
//				nextHour, 0, 0, 0, currentTime.Location())
//			return blockStart, blockEnd, i
//		}
//	}
//
//	// 不应该到这里
//	return currentTime, currentTime, -1
//}
//
//// getNextStandardTimeBlock 获取下一个标准的3小时时间块的开始时间
//func getNextStandardTimeBlock(currentTime time.Time) time.Time {
//	// 标准时间块的小时数
//	standardHours := []int{0, 3, 6, 9, 12, 15, 18, 21}
//
//	currentHour := currentTime.Hour()
//
//	// 查找严格大于当前小时的下一个标准时间块
//	for _, hour := range standardHours {
//		if hour > currentHour {
//			// 找到当天的下一个标准时间块
//			return time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(),
//				hour, 0, 0, 0, currentTime.Location())
//		}
//	}
//
//	// 如果当天没有更晚的标准时间块，返回第二天的00:00
//	nextDay := currentTime.Add(24 * time.Hour)
//	return time.Date(nextDay.Year(), nextDay.Month(), nextDay.Day(),
//		0, 0, 0, 0, currentTime.Location())
//}
//
//// calculatePlanningPeriods 计算从指定时间到目标时间的规划周期
//func calculatePlanningPeriods(startTime, endTime time.Time, periodDuration time.Duration) []PlanningPeriod {
//	var periods []PlanningPeriod
//
//	// 获取当前时间所在的标准块
//	currentBlockStart, currentBlockEnd, currentBlockIndex := getCurrentStandardBlock(startTime)
//
//	// 如果当前时间不在块的起始点，需要先添加部分块
//	if !startTime.Equal(currentBlockStart) && startTime.Before(currentBlockEnd) && currentBlockEnd.Before(endTime.Add(time.Minute)) {
//		// 添加部分时间块
//		partialDuration := currentBlockEnd.Sub(startTime)
//		usageFraction := divide(partialDuration.Hours(), 3.0)
//
//		periods = append(periods, PlanningPeriod{
//			Start:         startTime,
//			End:           currentBlockEnd,
//			IsPartial:     true,
//			BlockIndex:    currentBlockIndex,
//			BlockStart:    currentBlockStart,
//			UsageFraction: usageFraction,
//		})
//
//		// 从下一个标准块开始继续规划
//		startTime = currentBlockEnd
//	}
//
//	// 添加完整的标准时间块
//	currentTime := getNextStandardTimeBlock(startTime)
//	if startTime.Equal(currentBlockStart) || startTime.Equal(currentBlockEnd) {
//		// 如果已经在标准块的起点，直接从这里开始
//		currentTime = startTime
//	}
//
//	blockIndex := divide(float64(currentTime.Hour()), 3.0)
//
//	for currentTime.Before(endTime) {
//		blockEnd := currentTime.Add(periodDuration)
//
//		periods = append(periods, PlanningPeriod{
//			Start:         currentTime,
//			End:           blockEnd,
//			IsPartial:     false,
//			BlockIndex:    int(blockIndex),
//			BlockStart:    currentTime,
//			UsageFraction: 1.0,
//		})
//
//		currentTime = blockEnd
//		blockIndex++
//	}
//
//	return periods
//}
//
//// getPredictionIndex 根据当前时间计算在预测数组中的索引
//func getPredictionIndex(dayStartTime, currentTime time.Time, blockDuration time.Duration) int {
//	elapsed := currentTime.Sub(dayStartTime)
//	index := int(elapsed / blockDuration)
//	return index
//}
//
//// DailyPlanner 全天规划器
//type DailyPlanner struct {
//	planner                *Planner
//	startTime              time.Time
//	endTime                time.Time
//	initialLevel           float64
//	fullDayPrediction3h    []float64
//	fullDayPrediction30min []float64
//	nextDayPrediction3h    []float64
//}
//
//// NewDailyPlanner 创建一个全天规划器
//func NewDailyPlanner(rules UserRules, startTime time.Time, initialLevel float64,
//	prediction3h []float64, prediction30min []float64, nextDayPrediction3h []float64) *DailyPlanner {
//
//	planner := NewPlanner(rules, MinSafeLevelM3, MaxSafeLevelM3, InflowRateM3PerHour)
//
//	// 计算结束时间（当天24:00）
//	endTime := time.Date(startTime.Year(), startTime.Month(), startTime.Day(),
//		24, 0, 0, 0, startTime.Location())
//
//	// 如果开始时间已经是24:00或之后，则结束时间设为第二天24:00
//	if !startTime.Before(endTime) {
//		endTime = endTime.Add(24 * time.Hour)
//	}
//
//	return &DailyPlanner{
//		planner:                planner,
//		startTime:              startTime,
//		endTime:                endTime,
//		initialLevel:           initialLevel,
//		fullDayPrediction3h:    prediction3h,
//		fullDayPrediction30min: prediction30min,
//		nextDayPrediction3h:    nextDayPrediction3h,
//	}
//}
//
//// RunSimulation 运行从startTime到24:00的模拟
//// 【优化说明】此函数中所有fmt打印语句已替换为logMessage调用
//func (dp *DailyPlanner) RunSimulation() []*ReplenishmentTask {
//	// 【优化】使用logTitle替代fmt.Println
//	logTitle(LogLevelInfo, fmt.Sprintf("DAILY PLAN SIMULATION: %s -> 24:00", dp.startTime.Format(TimeLayout)))
//
//	// 计算规划周期（包含部分块和完整块）
//	planningPeriods := calculatePlanningPeriods(dp.startTime, dp.endTime, PlanningHorizon)
//
//	if len(planningPeriods) == 0 {
//		// 【优化】使用logMessage替代fmt.Println
//		logMessage(LogLevelInfo, "No planning periods needed (already at or past 24:00)\n")
//		return nil
//	}
//
//	// 【优化】使用logMessage替代fmt.Printf
//	logMessage(LogLevelInfo, "Start time: %s\n", dp.startTime.Format(TimeLayout))
//	if len(planningPeriods) > 0 {
//		if planningPeriods[0].IsPartial {
//			// 【优化】详细信息降为DEBUG级别
//			logMessage(LogLevelDebug, "First period: %s -> %s (PARTIAL BLOCK, %.1f%% of full block)\n",
//				planningPeriods[0].Start.Format(HourLayout),
//				planningPeriods[0].End.Format(HourLayout),
//				multiply(planningPeriods[0].UsageFraction, 100))
//			logMessage(LogLevelDebug, "  Block time range: %s -> %s\n",
//				planningPeriods[0].BlockStart.Format(HourLayout),
//				planningPeriods[0].End.Format(HourLayout))
//		} else {
//			logMessage(LogLevelDebug, "First period: %s -> %s (FULL BLOCK)\n",
//				planningPeriods[0].Start.Format(HourLayout),
//				planningPeriods[0].End.Format(HourLayout))
//		}
//	}
//	logMessage(LogLevelInfo, "Total planning periods: %d\n", len(planningPeriods))
//	// 【优化】使用logSubTitle替代fmt.Println
//	logSubTitle(LogLevelInfo)
//
//	allTasks := []*ReplenishmentTask{}
//	simulatedLevel := dp.initialLevel
//
//	// 获取当天00:00的时间，用于计算索引
//	//dayStart := time.Date(dp.startTime.Year(), dp.startTime.Month(), dp.startTime.Day(),
//	//	0, 0, 0, 0, dp.startTime.Location())
//
//	for i, period := range planningPeriods {
//		// 【关键修改】准备调整后的预测数据
//		adjustedPrediction3h := make([]float64, len(dp.fullDayPrediction3h)-period.BlockIndex)
//
//		if period.BlockIndex < len(dp.fullDayPrediction3h) {
//			// 复制从当前块开始的所有预测值
//			copy(adjustedPrediction3h, dp.fullDayPrediction3h[period.BlockIndex:])
//
//			// 如果是部分块，调整第一个预测值
//			if period.IsPartial && len(adjustedPrediction3h) > 0 {
//				originalBlockUsage := dp.fullDayPrediction3h[period.BlockIndex]
//				// 只保留剩余时间的用水量，使用multiply确保保留2位小数
//				adjustedPrediction3h[0] = multiply(originalBlockUsage, period.UsageFraction)
//
//				// 【优化】调整信息使用DEBUG级别
//				logMessage(LogLevelDebug, "  [Adjustment] Block %d (%s-%s): Full usage=%.2f m³, Remaining %.1f%% (%.2f m³)\n",
//					period.BlockIndex,
//					period.BlockStart.Format(HourLayout),
//					period.End.Format(HourLayout),
//					originalBlockUsage,
//					multiply(period.UsageFraction, 100),
//					adjustedPrediction3h[0])
//			}
//		} else {
//			// 如果索引超出范围，使用最后一个值估算
//			lastValue := 2.0
//			if len(dp.fullDayPrediction3h) > 0 {
//				lastValue = dp.fullDayPrediction3h[len(dp.fullDayPrediction3h)-1]
//			}
//			if period.IsPartial {
//				lastValue = multiply(lastValue, period.UsageFraction)
//			}
//			adjustedPrediction3h = []float64{lastValue, lastValue, lastValue}
//		}
//
//		// 构建系统状态，添加BlockStartTime字段
//		currentState := SystemState{
//			CurrentTime:         period.Start,
//			CurrentLevelM3:      simulatedLevel,
//			Prediction3h:        adjustedPrediction3h,
//			Prediction30min:     dp.fullDayPrediction30min,
//			NextDayPrediction3h: dp.nextDayPrediction3h,
//			BlockStartTime:      period.BlockStart, // 【关键】传入块的起始时间
//		}
//
//		// 判断是否是最后一个周期（21:00-24:00）
//		isLastPeriod := period.BlockIndex == 7
//
//		var task *ReplenishmentTask
//		if isLastPeriod {
//			task = dp.planner.GenerateLastPlan(currentState)
//		} else {
//			task = dp.planner.GeneratePlan(currentState)
//		}
//
//		// 计算本周期的实际用水量（用于模拟）
//		var usageInPeriod float64
//		if period.BlockIndex < len(dp.fullDayPrediction3h) {
//			baseUsage := dp.fullDayPrediction3h[period.BlockIndex]
//			// 按比例计算实际用水量
//			usageInPeriod = multiply(baseUsage, period.UsageFraction)
//		} else {
//			// 使用最后一个预测值
//			if len(dp.fullDayPrediction3h) > 0 {
//				baseUsage := dp.fullDayPrediction3h[len(dp.fullDayPrediction3h)-1]
//				usageInPeriod = multiply(baseUsage, period.UsageFraction)
//			} else {
//				usageInPeriod = multiply(2.0, period.UsageFraction)
//			}
//		}
//
//		refillInPeriod := 0.0
//		if task != nil {
//			allTasks = append(allTasks, task)
//			refillInPeriod = task.AmountM3
//
//			// 【优化】任务生成信息使用INFO级别
//			logMessage(LogLevelInfo, "=> Generated Task: [%s] Replenish %.2f m³ from %s to %s (%s)\n",
//				task.Priority, task.AmountM3,
//				task.StartTime.Format(HourLayout), task.EndTime.Format(HourLayout),
//				task.Reason)
//		} else {
//			// 【优化】无任务信息降为DEBUG级别
//			logMessage(LogLevelDebug, "=> No task generated for this period.\n")
//		}
//
//		// 更新模拟液位
//		nextSimulatedLevel := round2(simulatedLevel - usageInPeriod + refillInPeriod)
//
//		// 物理限制
//		if nextSimulatedLevel > MaxSafeLevelM3 {
//			nextSimulatedLevel = MaxSafeLevelM3
//		}
//		if nextSimulatedLevel < 0 {
//			nextSimulatedLevel = 0
//		}
//
//		blockType := "FULL"
//		if period.IsPartial {
//			blockType = fmt.Sprintf("PARTIAL(%.0f%%)", multiply(period.UsageFraction, 100))
//		}
//
//		// 【优化】周期统计使用INFO级别
//		logMessage(LogLevelInfo, "Period %d [%s -> %s] %s: StartLevel=%.2f, Usage=%.2f, Refill=%.2f, EndLevel=%.2f\n",
//			i+1,
//			period.Start.Format(HourLayout),
//			period.End.Format(HourLayout),
//			blockType,
//			simulatedLevel,
//			usageInPeriod,
//			refillInPeriod,
//			nextSimulatedLevel,
//		)
//		// 【优化】使用logSubTitle替代fmt.Println
//		logSubTitle(LogLevelInfo)
//
//		simulatedLevel = nextSimulatedLevel
//	}
//
//	// 【优化】使用logTitle替代fmt.Println
//	logTitle(LogLevelInfo, fmt.Sprintf("SIMULATION COMPLETE - Final Level: %.2f m³", simulatedLevel))
//
//	return allTasks
//}
